/**
 * Created by wangxiaodong on 2020-09-30
 *
 * 判定胡牌算法实现，js版本；用于前端
 *
 */

if (!Array.indexOf) {
    Array.prototype.indexOf = function (obj) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] == obj) {
                return i;
            }
        }
        return -1;
    };
}

/**
 * 删除数组中值为obj的元素，如果有obj元素，则删除第一个obj元素，且返回true, 如果没有，则不删除，且返回false
 */
if(!Array.remove) {
    Array.prototype.remove = function (obj) {
        var index = this.indexOf(obj);
        if(index > -1){
            this.splice(index,1);
            return true;
        } else {
            return false;
        }
    }
}

function sortNumber(a, b) {
    return a - b;
}

/**
 *
 * 判断出牌是否可碰
 * @param playingArray
 * @param mj
 * @returns {boolean}
 */
function isPeng(playingArray, mj){
    playingArray.sort(sortNumber);
    var count = 0;
    for(var i=0; i < playingArray.length; i++){
        if(playingArray[i] == mj){
            count = count + 1;
        }
    }

    if(count > 1){
        console.log("可碰：" + mj);
        return true;
    }
}

/**
 * 判断出牌是否可杠
 * @param playingArray
 * @param mj
 * @returns {boolean}
 */
function isGang(playingArray, mj){
    playingArray.sort(sortNumber);
    var count = 0;
    for(var i=0; i < playingArray.length; i++){
        if(playingArray[i] == mj){
            count = count + 1;
        }
    }

    if(count > 2){
        console.log("可杠：" + mj);
        return true;
    }
    return false;
}

/**
 * 获取可暗杠的牌
 * @param playingArray
 * @param yiPengArray
 * @returns {Array}
 */
function getAnGang(playingArray){
    var anGangArray = new Array();
    for(var i=0; i< playingArray.length; i++){
        var frequencyCount = frequency(playingArray, playingArray[i]);

        // 如果出现4次，即说明有暗杠
        if(frequencyCount == 4){
            // gangArray没有包含该元素时才添加，即只添加一次可杠的牌，不会添加4次
            if(anGangArray.indexOf(playingArray[i]) == -1){
                anGangArray[anGangArray.length] = playingArray[i];
            }
        }
    }

    return anGangArray;
}

/**
 * 获取可巴杠的牌
 * @param playingArray
 * @param yiPengArray
 */
function getBaGang(playingArray, yiPengArray){
    var baGangArray = new Array();
    for(var i=0; i<playingArray.length; i++){
        if(yiPengArray.indexOf(playingArray[i]) > -1){
            // 不用判断是否已存在，因为只可能还存在一个牌
            baGangArray[baGangArray.length] = playingArray[i];
        }
    }
    return baGangArray;
}

/**
 * 是否可以暗杠或者巴杠，摸牌是判断是看显示"杠"提示
 */
function isAnOrBaGang(playingArray, yiPengArray){
    var anGangArr = getAnGang(playingArray);
    var baGangArr = getBaGang(playingArray, yiPengArray);

    // 只有有一个可杠的牌，则返回true
    if((anGangArr.length + baGangArr.length) > 0){
        return true;
    }

    return false;
}

/**
 * 获取暗杠和巴杠的牌
 * @param playingArray
 * @param yiPengArray
 * @returns {Array}
 */
function getAnOrBaGang(playingArray, yiPengArray){
    var anGangArr = getAnGang(playingArray);
    var baGangArr = getBaGang(playingArray, yiPengArray);
    var anOrBaGangArr = anGangArr.concat(baGangArr);

    return anGangArr;
}

/**
 * 查询数组中某个元素出现的次数
 * @param array
 * @param element
 * @returns {number}
 */
function frequency(array, element){
    var count = 0;
    for(var i=0; i<array.length; i++){
        if(array[i] == element){
            count = count + 1;
        }
    }

    return count;
}

/**
 * 玩的完整的牌是否可以胡，即加上玩家新摸的牌，或者其他玩家打出的牌(总共14张，或者11张，8张，5张，2张)
 * @param wholeArray
 */
function isHu(wholeArray){
    var checkArr = new Array();
    checkArr = checkArr.concat(wholeArray);
    //console.log("checkArr.concat:" + checkArr);

    var pairArr = getPairs(checkArr);

    // 获取对牌后，checkArr中的元素已经被全部移除，需要重新放入
    checkArr = checkArr.concat(wholeArray);
    for(var i=0; i< pairArr.length; i++){
        var pair = pairArr[i];
        // 获取对牌的索引，用于删除对牌
        var pairIndex = checkArr.indexOf(pair);
        // 删除对牌：两个元素
        checkArr.splice(pairIndex, 2);

        // 表示只剩下对牌，能胡
        if(checkArr.length == 0){
            return true;
        }else{
            var is7Pair = true;
            // 判断7对，即剩下的12个牌是6对
            if(checkArr.length == 12){
                for(var j=0; j<checkArr.length - 1; j=j+2){
                    var first = checkArr[j];
                    var second = checkArr[j+1];
                    if(first != second){
                        is7Pair = false;
                    }
                }
            }else{  //剩下的牌少于12个牌，不可能是7对
                is7Pair = false;
            }

            if(is7Pair){
                console.log("7 对！");
                return true;
            }

            // 剩下的牌是否都满足AAA或者ABC
            var isHuPai = isAAAorABC(checkArr);
            if(isHuPai){
                return true;
            }else{
                // 重新将checkArr还原，判断下一组对牌做麻将的情况
                checkArr = new Array();
                checkArr = checkArr.concat(wholeArray);
            }
        }
    }

    return false;
}

/**
 * 判断某个牌是否可胡
 * @param holdArr
 * @param ting
 */
function isTing(holdArr, ting){
    // 不操作holdArr
    var operArr = new Array();
    operArr = operArr.concat(holdArr);

    // 将要判断的牌加入数组，看能不能组成胡牌
    operArr[operArr.length] = ting;

    // 加入新牌之后重新排序
    operArr.sort(operArr);

    return isHu(operArr);
}

function getAllTing(holdArr){
    var pai = new Array();
    for(var i=0; i<9; i++){
        pai[pai.length] = 11 + i;
        pai[pai.length] = 31 + i;
        pai[pai.length] = 51 + i;
    }

    var tingArr = new Array();
    for(var i=0; i< pai.length; i++){
        if(isTing(holdArr, pai[i])){
            tingArr[tingArr.length] = pai[i];
        }
    }

    return tingArr;
}

/**
 * 获取对牌
 * @param wholeArray
 * @returns {Array}
 */
function getPairs(wholeArray){
    var pairArray = new Array();
    for(var i=0; i<wholeArray.length; i++){
        var tmp = wholeArray.shift();
        i--;
        if(wholeArray.indexOf(tmp) > -1){
            if(pairArray.indexOf(tmp) < 0){
                pairArray.push(tmp);
            }
        }
    }

    return pairArray;
}

/**
 * 判断去除对牌(即麻将)之后，是否能够构成AAA或者ABC的牌型
 * @param operArray
 * @returns {boolean}
 */
function isAAAorABC(array){

    var operArray = new Array();
    operArray = operArray.concat(array);
    operArray.sort(sortNumber); // 必须基于已排序的数组
    var result = false;
    var ELEMENT1;
    var ELEMENT2;
    var ELEMENT3;
    if(operArray.length == 0){
        console.log("已检查完毕，满足AAA或ABC的要求");
        return true;
    }else{
        ELEMENT1 = operArray.shift();   // 获取并移除第一个元素
        ELEMENT2 = operArray.shift();   // 获取并移除第二个元素
        ELEMENT3 = operArray.shift();   // 获取并移除第三个元素
        if(ELEMENT1 == ELEMENT3){     // 已排序的数组，如果ELEMENT1==ELEMENT3，则必然ELEMENT1==ELEMENT2==ELEMENT3; 因此只需要判断一次即可
            console.log("存在 AAA:" + ELEMENT1);
            console.log("剩下需要继续判断的元素："+operArray);
            result = isAAAorABC(operArray);  // 存在AAA，继续递归剩下的元素
        }else{  // 不存在AAA，则判断ABC的情况

            // 还原数组
            operArray = new Array();
            operArray = operArray.concat(array);

            var A = operArray[0];
            var B = A + 1;
            var C = A + 2;

            operArray.remove(A);    // A 肯定存在
            var existB = operArray.remove(B);
            var existC = operArray.remove(C);

            if(existB && existC){ // 表示连续的，即可构成ABC
                console.log("存在ABC：" + ELEMENT1 + "," + ELEMENT2 + "," + ELEMENT3);
                console.log("剩下需要继续判断的元素："+operArray);
                result = isAAAorABC(operArray);
            }else{
                return false;
            }
        }
    }

    return result;
}

/** */
var array = new Array();
array.push(15);
array.push(15);
array.push(15);
array.push(16);
array.push(17);
array.push(31);
array.push(31);
array.push(32);
array.push(32);
array.push(33);
array.push(33);
array.push(56);
array.push(57);
array.push(58);
//array.push(12);

// 12,13,14,15,15,15,19,19,33,34,56,56,56; 32
// 15,15,15,16,17,31,31,32,32,33,33,56,57; 58

//var yiPengArray = new Array();
//yiPengArray.push(18);

console.log(array);
array.sort(sortNumber)
console.log(array);
//console.log(frequency(array, 16));
//console.log(isGang(array, 11));
//console.log(isPeng(array, 11));
//var anGang = getAnGang(array);
//console.log(anGang);
//console.log(getBaGang(array, yiPengArray));
//console.log("getPairs:" + getPairs(array));
//console.log(isAAAorABC(array));

//array.push(18);
//array.push(18);
// 12,13,14,15,15,15,19,19,33,34,56,56,56; 32
// 15,15,15,16,17,31,31,32,32,33,33,56,57; 58

console.log("isHu:" + isHu(array));
//console.log("isTing:" + isTing(array, 12));
//console.log("get all ting:" + getAllTing(array));
